/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*******************************************************************************
  * @file    wifi.c
  * @author  GEEKROS,  site:www.geekros.com
  ******************************************************************************
*/

#include "wifi.h"
#include "led.h"

/******************************************************************
  * @ 函数名称：Wifi_Init
  * @ 功能说明:ESP8266WiFi模块初始化，UART2作为WiFi模块专用接口
  *****************************************************************/
void Wifi_Init(int baud_rate)
{
    USART_InitTypeDef USART_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

    GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_USART2);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_USART2);

    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

    GPIO_Init(GPIOD, &GPIO_InitStructure);

    USART_DeInit(USART2);
    USART_StructInit(&USART_InitStructure);
    USART_InitStructure.USART_BaudRate = baud_rate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    USART_Init(USART2, &USART_InitStructure);
    USART_ITConfig(USART2, USART_IT_RXNE|USART_IT_IDLE, ENABLE);

    USART_Cmd(USART2, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

void USART2_IRQHandler(void)
{    
    u8 ucCh;

    if (USART_GetITStatus( USART2, USART_IT_RXNE ) != RESET ) {
        ucCh  = USART_ReceiveData( USART2 );
        if (ESP8266_Fram_Record_Struct .InfBit .FramLength < (RX_BUF_MAX_LEN - 1)) {
            ESP8266_Fram_Record_Struct .Data_RX_BUF[ ESP8266_Fram_Record_Struct .InfBit .FramLength ++ ]  = ucCh;
        }
    }
}

struct STRUCT_USART_Fram ESP8266_Fram_Record_Struct = { 0 };  // 定义了一个数据帧结构


void ESP8266_Send_AT_Cmd(char *cmd,u32 time)
{
    ESP8266_Fram_Record_Struct .InfBit .FramLength = 0; // 重新接收新的数据
    memset(ESP8266_Fram_Record_Struct .Data_RX_BUF,0,sizeof(ESP8266_Fram_Record_Struct .Data_RX_BUF));
    ESP8266_USART("%s\r\n", cmd);
    delay_ms(time);
}

void ESP8266_send_at(void)
{
    char cStr [20];
    sprintf ( cStr, "AT");
    ESP8266_Send_AT_Cmd( cStr,100);
}

void ESP8266_set_sta_mode(void)
{
    char cStr [20];
    sprintf ( cStr, "AT+CWMODE=1");
    ESP8266_Send_AT_Cmd( cStr,100);
}

void ESP8266_connect_wifi(void)
{
    char cStr [64];
    sprintf ( cStr, "AT+CWJAP=%s,%s",WIFI_SSID,WIFI_PASSWORD);
    Usb_Write_Data("SSID: %s  PWD: %s\r\n",WIFI_SSID,WIFI_PASSWORD);
    ESP8266_Send_AT_Cmd( cStr,5000);
}

void ESP8266_TCP_connect(void)
{
    char cStr [64];
    sprintf ( cStr, "AT+CIPSTART=\"TCP\",%s,%d",TCP_SERVICE_IP,TCP_COM);
    ESP8266_Send_AT_Cmd( cStr,1000);
}

void ESP8266_start_send(unsigned int len)
{
    char cStr [20];
    sprintf ( cStr, "AT+CIPSEND=%d",len);
    ESP8266_Send_AT_Cmd( cStr,50);
}

void ESP8266_close_tcp_connect(void)
{
    char cStr [20];
    sprintf ( cStr, "AT+CIPCLOSE");
    ESP8266_Send_AT_Cmd( cStr,200);
}

void ESP8266_send_data(char *dat,unsigned int len)
{
    ESP8266_start_send(len);  //start send

    ESP8266_USART("%s\r\n", dat);
}

// AT jiexi
static int  ESP8266AckDataDeal(u8 *pdat, u16 length, u8 *err)


    const char *src = (const char *)pdat;

    if (ESP8266_Fram_Record_Struct .InfBit .FramFinishFlag==1) {
        ESP8266_Fram_Record_Struct .InfBit .FramFinishFlag=0;
    }

    if (NULL != strstr(src, "+CIPSTART")) {
        if (strstr(src, "OK")) {
            ESP8266_Fram_Record_Struct .StateFlagBit .Connect_flag = 1;
        } else {
            ESP8266_Fram_Record_Struct .StateFlagBit .Connect_flag = 0;
        }
        return 0;
    } else if (NULL != strstr(src, "+CIPCLOSE")) {
        if (strstr(src, "OK")) {
            return 0;
        }
    } else if (NULL != strstr(src, "+CWMODE")) {
        if(strstr(src, "OK"))
        {
            ESP8266_Fram_Record_Struct .StateFlagBit.Sta_Mode = 1;
        }
        return 0;
    } else if (NULL != strstr(src, "+CWJAP")) {
        if (strstr(src, "CONNECTED")) {
            ESP8266_Fram_Record_Struct .StateFlagBit.Get_Ip_flag = 1;
        } else {
            ESP8266_Fram_Record_Struct .StateFlagBit.Get_Ip_flag = 0;
        }
        return 0;
    } else if (NULL != strstr(src, "+CIPMODE")) {
        if(strstr(src, "OK")) {
            ESP8266_Fram_Record_Struct .StateFlagBit.Trans_Mode = 1;
        }
        return 0;
    } else if (NULL != strstr(src, "+CIPSEND")) {
        if(strstr(src, "SEND OK")) {
            ESP8266_Fram_Record_Struct .StateFlagBit.Send_OK_flag = 1;
        } else {
            ESP8266_Fram_Record_Struct .StateFlagBit.Send_OK_flag = 0;
        }
        return 0;
    } else if (NULL != strstr(src, "OK")) {
        ESP8266_Fram_Record_Struct .StateFlagBit.ESP8266_Ready_flag = 1;
        return 0;
    }
    return -1;
}

signed char ESP8266_start_TCP(void)
{
    static unsigned char err = 0;
    char cStr [128];
    unsigned char reconnect_cnt;
    
    // AT
    Usb_Write_Data("ESP2866 TEST\r\n");
    err = 0;
    do {
        ESP8266_send_at();
        ESP8266AckDataDeal(ESP8266_Fram_Record_Struct.Data_RX_BUF, ESP8266_Fram_Record_Struct.InfBit.FramLength, &err);

        if (err++ > 5) {
            return -1;
        }
        GREEN_LED_TOGGLE();
    }while(!ESP8266_Fram_Record_Struct.StateFlagBit.ESP8266_Ready_flag);

    reconnect_cnt=0;
    RECONNECT:
    // AT+CIPCLOSE
    Usb_Write_Data("close tcp connect\r\n");
    err = 0;
    ESP8266_close_tcp_connect();

    // AT+CWMODE   set sta mode
    Usb_Write_Data("set sta mode\r\n");
    err = 0;
    do {
        ESP8266_set_sta_mode();
        ESP8266AckDataDeal(ESP8266_Fram_Record_Struct.Data_RX_BUF, ESP8266_Fram_Record_Struct.InfBit.FramLength, &err);
        if (err++ > 5) {
            return -1;
        }
        GREEN_LED_TOGGLE();
    }while(!ESP8266_Fram_Record_Struct.StateFlagBit.Sta_Mode);

    // AT+CWJAP
    Usb_Write_Data("connecting wifi......\r\n");
    err = 0;
    ESP8266_Fram_Record_Struct.StateFlagBit.Get_Ip_flag=0;
    do {
        ESP8266_connect_wifi();
        ESP8266AckDataDeal(ESP8266_Fram_Record_Struct.Data_RX_BUF, ESP8266_Fram_Record_Struct.InfBit.FramLength, &err);
        if (err++ > 5) {
            return -1;
        }
        GREEN_LED_TOGGLE();
    }while(!ESP8266_Fram_Record_Struct.StateFlagBit.Get_Ip_flag);

    // AT+CIPSTART
    Usb_Write_Data("building  tcp connect......\r\n");
    err = 0;
    ESP8266_Fram_Record_Struct.StateFlagBit.Connect_flag=0;
    do {
        ESP8266_TCP_connect();
        ESP8266AckDataDeal(ESP8266_Fram_Record_Struct.Data_RX_BUF, ESP8266_Fram_Record_Struct.InfBit.FramLength, &err);
        if (err++ > 5) {
            //return -1;
            reconnect_cnt++;
            Usb_Write_Data("reconnect_cnt = %d\r\n",reconnect_cnt);
            if (reconnect_cnt<5) {
                goto RECONNECT;
            } else {
                return -1;
            }
        }
        GREEN_LED_TOGGLE();
    }while(!ESP8266_Fram_Record_Struct.StateFlagBit .Connect_flag);

    Usb_Write_Data("ESP8266 ok!!!\r\n");
    sprintf (cStr, "ESP8266 init success");
    Usb_Write_Data("cStr length: %d\r\n",strlen(cStr));
    ESP8266_send_data(cStr,strlen(cStr));
    
  return 0;
}

static char *itoa( int value, char *string, int radix )
{
    int     i, d;
    int     flag = 0;
    char    *ptr = string;

    /* This implementation only works for decimal numbers. */
    if (radix != 10) {
        *ptr = 0;
        return string;
    }

    if (!value) {
        *ptr++ = 0x30;
        *ptr = 0;
        return string;
    }

    /* if this is a negative value insert the minus sign. */
    if (value < 0) {
        *ptr++ = '-';

        /* Make the value positive. */
        value *= -1;
    }

    for (i = 10000; i > 0; i /= 10) {
        d = value / i;
        if (d || flag) {
            *ptr++ = (char)(d + 0x30);
            value -= (d * i);
            flag = 1;
        }
    }

    /* Null terminate the string. */
    *ptr = 0;

    return string;

} /* NCL_Itoa */

void USART_printf ( USART_TypeDef * USARTx, char * Data, ... )
{
    const char *s;
    int d;
    char buf[16];
    va_list ap;
    va_start(ap, Data);

    while ( * Data != 0 ) {
        if ( * Data == 0x5c ) {   //'\'
            switch (*++Data) {
                case 'r':
                USART_SendData(USARTx, 0x0d);
                Data ++;
                break;

                case 'n':
                USART_SendData(USARTx, 0x0a);
                Data ++;
                break;

                default:
                Data ++;
                break;
            }
        } else if ( * Data == '%') {
            switch ( *++Data ) {
                case 's':
                s = va_arg(ap, const char *);
                for ( ; *s; s++) {
                    USART_SendData(USARTx,*s);
                    while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET) {
                        ;
                    }
                }
                Data++;
                break;

                case 'd':
                d = va_arg(ap, int);
                itoa(d, buf, 10);
                for (s = buf; *s; s++) {
                    USART_SendData(USARTx,*s);
                    while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET) {
                        ;
                    }
                }
                     Data++;
                     break;
                default:
                     Data++;
                     break;
            }
        } else {
            USART_SendData(USARTx, *Data++);
            while (USART_GetFlagStatus (USARTx, USART_FLAG_TXE) == RESET) {
            ;
            }
        }
    }
}


